package com.sky.sd.system.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.netflix.discovery.converters.Auto;
import com.sky.sd.common.exception.ServiceException;
import com.sky.sd.system.bean.dto.DeptNode;
import com.sky.sd.system.bean.dto.MenuNode;
import com.sky.sd.system.bean.dto.UserDto;
import com.sky.sd.system.bean.po.Dept;
import com.sky.sd.system.bean.po.Menu;
import com.sky.sd.system.bean.po.User;
import com.sky.sd.system.bean.vo.DeleteVo;
import com.sky.sd.system.bean.vo.DeptAddVo;
import com.sky.sd.system.bean.vo.DeptSearchVo;
import com.sky.sd.system.bean.vo.DeptUpdateVo;
import com.sky.sd.system.constant.SystemConstant;
import com.sky.sd.system.dao.DeptMapper;
import com.sky.sd.system.dao.UserMapper;
import com.sky.sd.system.enums.IsDefaultType;
import com.sky.sd.system.enums.MenuType;
import com.sky.sd.system.service.IDeptService;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.bouncycastle.jcajce.provider.symmetric.AES;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.parameters.P;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 部门 服务实现类
 * </p>
 *
 * @author 弓振
 * @since 2020-07-03
 */
@Service
public class DeptServiceImpl extends ServiceImpl<DeptMapper, Dept> implements IDeptService {

    @Autowired
    private UserMapper userMapper;

    @Override
    public IPage<DeptNode> listDeptPage(DeptSearchVo vo) {
        IPage<DeptNode> page = new Page<>(vo.getPageNum(), vo.getPageSize());
        page = baseMapper.listDeptPage(page, Wrappers.<Dept>lambdaQuery()
                .eq(Dept::getParentId, SystemConstant.TOP_PARENT_ID).eq(Dept::getIsDel, IsDefaultType.NO));
        List<Dept> depts = baseMapper.selectList(Wrappers.<Dept>lambdaQuery().ne(Dept::getParentId, SystemConstant.TOP_PARENT_ID));
        initTree(page.getRecords(), depts);
        return page;
    }

    @Override
    public int checkParentId(String parentId,String id) {
        return assertChildNode(parentId, id);
    }

    @Override
    public void add(DeptAddVo vo) {
        canUpdate(vo.getId(), vo.getDeptName());

        Dept parentDept = baseMapper.selectById(vo.getParentId());
        if(parentDept == null) {
            throw new ServiceException("查不到父部门");
        }

        Dept dept = new Dept();
        BeanUtils.copyProperties(vo, dept);
        baseMapper.insert(dept);
    }

    @Override
    public void update(DeptUpdateVo vo) {
        canUpdate(vo.getId(), vo.getDeptName());

        Dept dept = new Dept();
        BeanUtils.copyProperties(vo, dept);

        // 判断父节点是否改变，改变->判断当前选中节点是否为该节点下子节点，如果是，则返回失败
        Dept curDept = baseMapper.selectById(vo.getId());
        if(!curDept.getParentId().equals(vo.getParentId())) {
            int result = assertChildNode(vo.getParentId(), vo.getId());
            if(result > 0) {
                throw new ServiceException("不能选择该节点下子节点");
            }
            updateChild(dept);
        } else {
            baseMapper.updateById(dept);
        }
    }

    @Override
    public void updateEnabled(DeptUpdateVo vo) {
        Dept dept = new Dept();
        BeanUtils.copyProperties(vo, dept);
        updateChildEnabled(dept);
    }

    @Override
    public void delete(DeleteVo vo) {
        // 查询部门及其子部门是否关联用户
        int userCnt = assertChildDeptOfUser(vo.getIds().iterator().next());
        if(userCnt > 0) {
            throw new ServiceException("该部门下关联的有用户，不能删除");
        }

        // 删除部门及其子部门
        deleteChildDept(vo.getIds().iterator().next());
    }

    private void initTree(List<DeptNode> topDepts, List<Dept> depts) {
        // 父类向子类转换
        List<DeptNode> deptNodes = depts.parallelStream().map(dept -> {
            DeptNode deptTree = new DeptNode();
            BeanUtils.copyProperties(dept, deptTree);
            return deptTree;
        }).collect(Collectors.toList());

        // 创建树
        if(CollectionUtils.isNotEmpty(topDepts)) {
            topDepts.parallelStream().forEach(deptNode -> {
                createDeptTree(deptNode, deptNodes);
            });
        }
    }

    private void createDeptTree(DeptNode curDeptNode, List<DeptNode> allMeptNodes) {
        List<DeptNode> nextDeptNodes = allMeptNodes.parallelStream()
                .filter(menuNode -> StringUtils.equals(curDeptNode.getId(),menuNode.getParentId()))
                .sorted().collect(Collectors.toList());
        nextDeptNodes.parallelStream().forEach(deptNode -> {
            createDeptTree(deptNode, allMeptNodes);
        });
        if(CollectionUtils.isNotEmpty(nextDeptNodes)) {
            curDeptNode.setChildren(nextDeptNodes);
        }
    }

    /**
     * 判断parentId是否是id的节点或id的子节点
     * @param parentId
     * @param id
     * @return
     */
    private int assertChildNode(String parentId,String id) {
        if(StringUtils.equals(parentId, id)) {
            return 1;
        }

        List<Dept> childDepts = baseMapper.selectList(Wrappers.<Dept>lambdaQuery().eq(Dept::getParentId,id));
        int result = 0;
        for(int i = 0;i < childDepts.size();i++) {
            result = assertChildNode(parentId, childDepts.get(i).getId());
            if(result > 0) {
                return result;
            }
        }
        return 0;
    }

    /**
     * 更新当前节点及其子节点
     * @param dept
     */
    private void updateChild(Dept dept) {
        baseMapper.updateById(dept);
        List<Dept> childDepts = baseMapper.selectList(Wrappers.<Dept>lambdaQuery().eq(Dept::getParentId,dept.getId()));
        childDepts.parallelStream().forEach(childDept -> {
            Dept tmpDept = new Dept();
            tmpDept.setId(childDept.getId());
            updateChild(tmpDept);
        });
    }

    /**
     * 更新当前节点及其字节
     * @param dept
     */
    private void updateChildEnabled(Dept dept) {
        baseMapper.updateById(dept);
        List<Dept> childDepts = baseMapper.selectList(Wrappers.<Dept>lambdaQuery().eq(Dept::getParentId,dept.getId()));
        childDepts.parallelStream().forEach(childDept -> {
            Dept tmpDept = new Dept();
            tmpDept.setId(childDept.getId());
            tmpDept.setEnabled(dept.getEnabled());
            updateChildEnabled(tmpDept);
        });
    }

    /**
     * 判断当前节点及其字节带你是否关联用户
     * @param parentId
     * @return
     */
    private int assertChildDeptOfUser(String id) {
        int userCnt = userMapper.selectCount(Wrappers.<User>lambdaQuery().eq(User::getDeptId, id));
        if(userCnt > 0) {
            return userCnt;
        }

        List<Dept> childDepts = baseMapper.selectList(Wrappers.<Dept>lambdaQuery().eq(Dept::getParentId, id));
        int result = 0;
        for(int i = 0;i < childDepts.size();i++) {
            result = assertChildDeptOfUser(childDepts.get(i).getId());
            if(result > 0) {
                return result;
            }
        }
        return result;
    }

    /**
     * 删除当前节点及其字节
     * @param dept
     */
    private void deleteChildDept(String parentId) {
        baseMapper.deleteById(parentId);
        List<Dept> childDepts = baseMapper.selectList(Wrappers.<Dept>lambdaQuery().eq(Dept::getParentId, parentId));
        childDepts.parallelStream().forEach(dept -> {
            deleteChildDept(dept.getId());
        });
    }

    private void canUpdate(String id, String deptName) {
        int deptNameCnt = baseMapper.selectCount(Wrappers.<Dept>lambdaQuery()
                .ne(StringUtils.isNoneBlank(id), Dept::getId, id).eq(Dept::getDeptName, deptName));
        if(deptNameCnt > 0) {
            throw new ServiceException("部门编码已存在");
        }
    }
}
